package com.gthncz.service;

import java.io.IOException;
import java.time.Instant;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.stereotype.Service;

import com.gthncz.common.CommonResult;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Service
public class JWTAuthenticationService {
	
	private static final Logger log = LoggerFactory.getLogger(JWTAuthenticationService.class);
	
	/**
	 * 2 min
	 */
	private final long EXPIRATION_TIME = 2*60*1000;
	
	/**
	 * JWT 签名密码
	 */
	private final String JWT_SECRET = "P@SSW02D";
	
	/**
	 * Token 前缀
	 */
	private final String TOKEN_PREFIX = "Bearer";
	
	/**
	 * 请求头中携带 JWT 的 键名
	 */
	private final String HEADER_FIELD = "Authorization";
	
	/**
	 * 生成 jwt
	 * @param username
	 * @return
	 */
	public String generateJwt(String username) {
		return Jwts.builder()
				// 保存权限/角色， 多个权限/角色使用 `,` 分隔
				.claim("Authorization", "AUTH_WRITE,ROLE_ADMIN")
				// 用户名写入主题
				.setSubject(username)
				// 设置过期时间
				.setExpiration(new Date(Instant.now().toEpochMilli() + EXPIRATION_TIME))
				// 签名 
				.signWith(SignatureAlgorithm.HS512, JWT_SECRET)
				.compact();
	}
	
	/**
	 * 认证
	 * @param request
	 * @throws IOException 
	 */
	public void addAuthentication(HttpServletResponse response, String username) throws IOException {
		log.warn("> JWTAuthenticationService addAuthentication: {}", username);
		
		String JWT = generateJwt(username);
		response.setHeader("Content-Type", "application/json");
		response.setStatus(HttpServletResponse.SC_OK);
		response.getOutputStream().println(new CommonResult(200, "OK", JWT).toJson());
	}
	
	/**
	 * 从 token 中解析出 Claims
	 * @param token
	 * @return
	 */
	public Claims extranctClaims(String token) throws ExpiredJwtException {
		Claims claims = Jwts.parser()
				// 验签
				.setSigningKey(JWT_SECRET)
				// 解析 Claims
				// UnsupportedJwtException: Signed Claims JWSs are not supported. 错误
				// parseClaimsJws(String) 用于处理 签名后的 token
				// parseClaimsJwt(String) 用于处理 未签名的 token
				.parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
				.getBody();
		return claims;
	}
	
	/**
	 * 获取认证
	 * @param request
	 * @return
	 */
	public Authentication getAuthentication(HttpServletRequest request) throws ExpiredJwtException {
		String token = request.getHeader(HEADER_FIELD);
		
		log.warn("> JWTAuthenticationService getAuthentication: {}", token);
		
		if (null != token) {
			Claims claims = extranctClaims(token);
			
			// 获取 username
			String username = claims.getSubject();
			
			// 获取 权限/角色
			List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("Authorization"));
			
			// 获取验证令牌
			return null != username ? 
					new UsernamePasswordAuthenticationToken(username, null, authorities) : null;
		}
		
		return null;
	}
	
}
